#ifndef SOCKET_H
#define SOCKET_H
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdint.h>
#include <netdb.h>
#include <netinet/in.h>
#endif

#ifndef VECTOR_H
#define VECTOR_H
#include <vector>
#endif

#ifndef MAP_H
#define MAP_H
#include <map>
#endif

#ifndef TIME_OUT_H
#define TIME_OUT_H
#include "../Timeout/Timeout.h"
#endif

#define BACKLOG_MAX 10

#ifndef VECTOR_H
#define VECTOR_H
#include <vector>
#endif

#ifndef FILE_H
#define FILE_H
#include <iostream>
#include <fstream>
#endif

#include <string.h>
#include <string>

#ifndef TFTP_H
#define TFTP_H
#include "../Headers/TFTP.h"
#endif

#ifndef ERROR_H
#define ERROR_H
#include "../Errors/errors.h"
#endif

#define RETRY_LIMIT 		4
#define FIRST_INTERVAL		2

using namespace std;

class FileTransfer {
	sockaddr_in client;
	std::ifstream file;
	std::vector<char> current_block;
	unsigned short block_no;
public:
	int sock;
	int result;
	bool finished;
	void get_next_block();
	void send_next_block();
	void read();
	void ack(unsigned short block_no);
	void send_file_not_found();
	void close_ft();
	struct timeval last_time;
	struct timeval current_time;
	int retry_time;
	long interval;
	bool is_open;

	FileTransfer(sockaddr_in* _client, const char* _file) {
		result = 0;
		finished = false;
		block_no = 1;
		sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		memcpy(&client, _client, sizeof(struct sockaddr_in));
		file.open(_file, std::ios::in | std::ios::binary);
		// Check if file opened ok
		if(!file.is_open()) {
			result = -1;
			finished = true;
			set_error((string("Failed to open file: ")+string(_file)).c_str());
			send_file_not_found();
			is_open = false;
		}else{
			gettimeofday(&last_time,NULL);
			retry_time = 0;
			get_next_block();
			printf("%s\n", _file);
			is_open = true;
		}
		
	}
};

class Server {
	struct sockaddr_in myaddr;
	unsigned short port;
	std::string server_dir;

public:
	int incoming_sock;
	std::map<int, FileTransfer*> transfers;
	std::map<int, FileTransfer*>::iterator trans_it;
	struct timeval tv;
	int retry_limit;
	int first_interval;

	Server(char * _host, unsigned short _port, string _server_dir)
	:port(_port), server_dir(_server_dir) {
		myaddr.sin_family = AF_INET;
		myaddr.sin_port = htons(port);
		inet_aton(_host, &myaddr.sin_addr);

		incoming_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		result = bind(incoming_sock,
						(struct sockaddr*)&myaddr,
						sizeof(struct sockaddr_in));
		printf("incoming sockfd: %d\n", incoming_sock);
		if(result < 0) {
			auto_set_error("Error creating server");
		}
	}

	static std::vector<char> read(int _sock, struct sockaddr_in* src);
	static void send(int _sock, struct sockaddr_in* src, std::vector<char> data);
	static Packet* read_packet(int _sock, struct sockaddr_in* _src);
	void stop_server();
	void start_transfer(int sock);
	int handle_transfer(int sock);
	int new_file_transfer(struct sockaddr_in* _client, const char* _filename);
	void handle_server_connection();
	int handle_select_timout(FileTransfer* ft);
	int handle_interval(FileTransfer* ft);
};

